package org.hepeng.workx.bean.factory;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.reflections.Reflections;
import org.springframework.util.Assert;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * @author he peng
 */

public class ClassPathObjectFactory implements ObjectFactory {

    @Override
    public <T> T getInstance(Class<T> type) throws Exception {
        return getInstance(type , null , null);
    }

    @Override
    public <T> T getInstance(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) throws Exception {
        Assert.notNull(type , "type must not be null");
        T instance = null;
        if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) {
            Reflections reflections = new Reflections();
            Set<Class<? extends T>> subTypes = reflections.getSubTypesOf(type);
            if (CollectionUtils.isNotEmpty(subTypes)) {
                for (Class<? extends T> subType : subTypes) {
                    if (subType.isInterface() || Modifier.isAbstract(subType.getModifiers())) {
                        continue;
                    }
                    try {
                        Class<?>[] argTypes = org.hepeng.workx.util.ConstructorUtils.argTypeToArray(constructorArgTypes);
                        Object[] args = org.hepeng.workx.util.ConstructorUtils.argToArray(constructorArgs);
                        instance = ConstructorUtils.invokeConstructor(subType , args , argTypes);
                    } catch (Exception e) {
                        continue;
                    }
                }
            }
        } else {
            Class<?>[] argTypes = org.hepeng.workx.util.ConstructorUtils.argTypeToArray(constructorArgTypes);
            Constructor<T> constructor = ConstructorUtils.getAccessibleConstructor(type , argTypes);
            if (Objects.nonNull(constructor)) {
                Object[] args = org.hepeng.workx.util.ConstructorUtils.argToArray(constructorArgs);
                instance = ConstructorUtils.invokeConstructor(type , args , argTypes);
            }
        }

        return instance;
    }

    @Override
    public <T> List<Class<? extends T>> getInstances(Class<T> cls) {
//        Reflections reflections = ReflectionsUtils.getAllClassReflections();
//        Set<Class<? extends T>> subTypesOf = reflections.getSubTypesOf(cls);
        return null;
    }

    @Override
    public <T> List<Class<? extends T>> getInstances(Class<T> cls, String packageName) {
        return null;
    }

    @Override
    public List<Class> getInstancesWithAnnotation(Class<? extends Annotation> annotationClass) {
        return null;
    }

    @Override
    public List<Class> getInstancesWithAnnotation(Class<? extends Annotation> annotationClass, String packageName) {
        return null;
    }
}
